﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ServiceBus;
using System.ServiceModel;
using nwrole.toolbox.sync.ServiceHost;
using nwrole.toolbox.sync.contract;
using nwrole.toolbox.sync.entity;

namespace nwrole.toolbox.sync.client
{
    public class SyncSourceServiceClient
    {
        /*private bool runLocal;
        private string sbServiceNamespace;
        private string sbServicePath;
        private string sbIssuerName;
        private string sbIssuerSecret;
        private string localServicePath;*/

        private ServiceConnectionInfo connInfo;

        public SyncSourceServiceClient(ServiceConnectionInfo connectionInfo)
        {
            connInfo = connectionInfo;
        }

        /*/// <summary>
        /// Connects to a sync source running locally
        /// </summary>
        public SyncSourceServiceClient(string servicePath)
        {
            runLocal = true;
            localServicePath = servicePath;
        }
        
        /// <summary>
        /// Connects to a sync source over Azure Service Bus
        /// </summary>
        /// <param name="sbServiceNamespace">Service namespace</param>
        /// <param name="sbServicePath">Service path</param>
        /// <param name="sbIssuerName">Service issuer name</param>
        /// <param name="sbIssuerSecret">Service issuer secret</param>
        public SyncSourceServiceClient(string sbServiceNamespace, string sbServicePath, string sbIssuerName, string sbIssuerSecret)
        {
            runLocal = false;
            this.sbServiceNamespace = sbServiceNamespace;
            this.sbServicePath = sbServicePath;
            this.sbIssuerName = sbIssuerName;
            this.sbIssuerSecret = sbIssuerSecret;
        }*/

        public bool StartFullSync(int instanceId)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            bool result = serviceChannel.StartFullSync(instanceId);

            serviceChannel.Close();

            return result;
        }
        
        public bool SyncNextEntity(int instanceId)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.SyncNextEntity(instanceId);

            serviceChannel.Close();
            return result;
        }

        /*public string SyncAllSyncEntities()
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.SyncAllSyncEntities();

            serviceChannel.Close();
            return result;
        }*/

        public string SyncSyncEntity(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.SyncSyncEntity(id);

            serviceChannel.Close();
            return result;
        }


        public string DeploySource(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.DeploySource(id);

            serviceChannel.Close();
            return result;
        }

        public string DeleteSyncEntity(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.DeleteSyncEntity(id);

            serviceChannel.Close();
            return result;
        }

        public bool DeploySourceEnvironment()
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.DeploySourceEnvironment();

            serviceChannel.Close();
            return result;
        }

        /*public string DeployDestEnvironment()
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.DeployDestEnvironment();

            serviceChannel.Close();
            return result;
        }*/

        public SyncEntity ImportSchema(int syncInstanceId, long schemaId, short type)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.ImportSchema(syncInstanceId, schemaId, type);

            serviceChannel.Close();
            return result;
        }

        public SyncEntity GetSchemaEntity(long id, short type)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetSchemaEntity(id, type);

            serviceChannel.Close();
            return result;
        }


        public bool ToggleSyncEnabled(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.ToggleSyncEnabled(id);

            serviceChannel.Close();
            return result;
        }

        public SyncModeEnum ToggleSyncMode(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.ToggleSyncMode(id);

            serviceChannel.Close();
            return result;
        }

        public bool ToggleSyncColumnEnabled(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.ToggleSyncColumnEnabled(id);

            serviceChannel.Close();
            return result;
        }

        public void ToggleAllSyncColumnEnabled(long syncEntityId)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            serviceChannel.ToggleAllSyncColumnEnabled(syncEntityId);

            serviceChannel.Close();
        }

        public void Update(SyncEntity entity)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            serviceChannel.Update(entity);

            serviceChannel.Close();
        }

        public List<SyncEntity> GetSchemaEntities(int page = 0, int pagesize = 1500)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetSchemaEntities(page, pagesize);

            serviceChannel.Close();
            return result;
        }

        public List<SyncEntity> GetEntities(int syncInstanceId)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetEntities(syncInstanceId);

            serviceChannel.Close();
            return result;
        }

        public SyncEntity GetEntityById(long id)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetEntityById(id);

            serviceChannel.Close();
            return result;
        }

        public DeployStatus GetDeployStatus()
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetDeployStatus();

            serviceChannel.Close();
            return result;
        }

        public string GetSettingStringValue(string key)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetSettingStringValue(key);

            serviceChannel.Close();
            return result;
        }

        public void SetSettingValue(string key, string value)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            serviceChannel.SetSettingValue(key, value);

            serviceChannel.Close();
        }
        

        /*public SyncEntity GetEntityById(string name)
        {
            ISyncSourceServiceChannel serviceChannel = GetChannel();
            serviceChannel.Open();

            var result = serviceChannel.GetEntityByName(name);

            serviceChannel.Close();
            return result;
        }*/

        private ISyncSourceServiceChannel GetChannel()
        {
            if (connInfo.Type == ServiceConnectionInfo.ServiceConnectionType.WebService)
                return GetChannelWebService();

            return GetChannelServiceBus();
        }

        private ISyncSourceServiceChannel GetChannelServiceBus()
        {
            ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.AutoDetect;

            Uri serviceUri = ServiceBusEnvironment.CreateServiceUri("sb", connInfo.ServiceBusServiceNamespace, connInfo.ServiceBusServicePath);

            Console.WriteLine("Connecting to {0} address: {1}", "MyName", serviceUri);


            TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();

            sharedSecretServiceBusCredential.TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(connInfo.ServiceBusIssuerName, connInfo.ServiceBusIssuerSecret);

            ChannelFactory<ISyncSourceServiceChannel> channelFactory = new ChannelFactory<ISyncSourceServiceChannel>();
            channelFactory.Endpoint.Address = new EndpointAddress(serviceUri);

            NetTcpRelayBinding binding = new NetTcpRelayBinding();
            binding.ReceiveTimeout = new TimeSpan(0, 0, 120);
            binding.MaxConnections = 100;
            binding.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
            binding.MaxReceivedMessageSize = 2000000;
            binding.MaxBufferPoolSize = 2000000;
            binding.ReaderQuotas.MaxStringContentLength = 2000000;
            binding.ReaderQuotas.MaxArrayLength = 2000000;

            binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
            binding.SendTimeout = new TimeSpan(0, 10, 0);

            channelFactory.Endpoint.Binding = binding;

            channelFactory.Endpoint.Contract.ContractType = typeof(ISyncSourceServiceChannel);

            channelFactory.Endpoint.Behaviors.Add(sharedSecretServiceBusCredential);

            ISyncSourceServiceChannel serviceChannel = channelFactory.CreateChannel();
            return serviceChannel;
        }

        private ISyncSourceServiceChannel GetChannelWebService()
        {
            NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
            //binding.MaxReceivedMessageSize = 2000000;
            //binding.MaxBufferPoolSize = 2000000;

            binding.MaxConnections = 100;
            binding.ReaderQuotas = System.Xml.XmlDictionaryReaderQuotas.Max;
            binding.MaxBufferSize = 200000000;
            binding.MaxReceivedMessageSize = 200000000;
            binding.MaxBufferPoolSize = 200000000;
            binding.ReaderQuotas.MaxDepth = 32;
            binding.ReaderQuotas.MaxArrayLength = 200000000;
            binding.ReaderQuotas.MaxStringContentLength = 200000000;


            binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
            binding.SendTimeout = new TimeSpan(0, 10, 0);

            //ChannelFactory<ISyncSourceServiceChannel> httpFactory = new ChannelFactory<ISyncSourceServiceChannel>(binding, new EndpointAddress("net.tcp://localhost:8086/JFTestService"));
            ChannelFactory<ISyncSourceServiceChannel> httpFactory = new ChannelFactory<ISyncSourceServiceChannel>(binding, new EndpointAddress("net.tcp://" + connInfo.WebServiceBaseAddress + connInfo.WebServiceAddress));
            // DuplexChannelFactory<IRemoteWebContract> httpFactory = new DuplexChannelFactory<IRemoteWebContract>(callback, new NetTcpBinding(SecurityMode.None), new EndpointAddress("net.tcp://localhost:8083/RemoteService"));
            //DuplexChannelFactory<IRemoteWebContract> httpFactory = new DuplexChannelFactory<IRemoteWebContract>(callback, new NetNamedPipeBinding(), 
            //                                    new EndpointAddress("net.pipe://localhost/RemoteService"));
            return httpFactory.CreateChannel();
        }
    }
}

